/** @file    MessageProcessingCommon.cpp
 *  @author  Alessandro Polo
 *  @version $Id: MessageProcessingCommon.cpp 2823 2010-08-01 13:35:42Z alex $
 *  @brief
 * File containing implementations of file MessageProcessingCommon.h
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

 #include <core/MessageProcessingCommon.h>

 #include <core/List.h>
 #include <core/Table.h>
 #include <core/SecurityManager.h>
 #include <core/UserManager.h>


using namespace std;
namespace wosh {

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

Message* MPC_busMessageRequest( const Message& requestMessage, MethodsProvider& Methods, LogContext& Log )
 {
	if ( requestMessage.isEmpty() || !requestMessage.getContent()->isRequest() ) return NULL;
	MutexLockerRead mL(Methods.getMutex());
	// lock invalidating operations (REMOVAL; List::Permission updates)
	bool allowread = SecurityManager::evalAuthorization( requestMessage.getSecurityToken(), &Methods.getListPermission(), Permission::Read );
	if ( !allowread ) // also validated missing security token
		return NULL; // silent
	const Request* request = requestMessage.getContent()->asRequest();
	Method* method = Methods.find( request->getMethod() );
	if ( method == NULL ) {
		Log(LOG_WARNING, ":busMessage() FAILED : Method '%s' not found", request->getMethod().c_str() );
		if ( request->doOmitResponse() ) return NULL;
		return requestMessage.replyTo( request->replyResponse(WRET_ERR_PARAM, Utilities::format("Method '%s' not found!", request->getMethod().c_str()).c_str()) );
	 }
	// read the permission, lock it for reading
	method->transactionBeginRead();
	bool allowRead = SecurityManager::evalAuthorization( requestMessage.getSecurityToken(), &method->getPermission(), Permission::Read );
	if ( !allowRead ) {
		method->transactionEnd();
		Log(LOG_WARNING, ":busMessage() : Not allowed to read method '%s' ", request->getMethod().c_str() );
		return NULL; // silent
	 }
	bool allowExec = SecurityManager::evalAuthorization( requestMessage.getSecurityToken(), &method->getPermission(), Permission::Execute );
	if ( !allowExec ) {
		method->transactionEnd();
		Log(LOG_WARNING, ":busMessage() : Not allowed to exec method '%s' ", request->getMethod().c_str() );
		if ( request->doOmitResponse() ) return NULL;
		return requestMessage.replyTo( request->replyResponse(WRET_ERR_ILLEGAL_USE, "Not allowed to exec method") );
	 }
	// call the message
	Log(LOG_DEBUG, ":busMessage() : Executing '%s'", request->getMethod().c_str() );
	Message* reply = method->exec( &requestMessage );
	Log(LOG_DEBUG, ":busMessage() : Executed '%s' (%d)", request->getMethod().c_str(), (int)(reply!=NULL) );
	// we are done
	method->transactionEnd();
	// return reply (if any)
	if ( reply != NULL && request->doOmitResponse() ) {
		delete reply; reply = NULL;
	 }
	return reply;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool MPC_PropertyParse_LogLevel( const Variant& value_proposed, LogContext& Log ) {
	LogLevel level = LOG_UNKNOWN;
	if ( value_proposed.isNumeric() )
		level = static_cast<LogLevel>( value_proposed.toInteger( (int)LOG_UNKNOWN ) );
	else if ( value_proposed.isString() )
		level = LogContext::getLogLevelFromString( value_proposed.asString().c_str() );
	if ( level <= LOG_UNKNOWN || level > LOG_ALL ) return false;
	Log(LOG_WARNING, " Changing Debug-Level to '%s'", value_proposed.toString().c_str() );
	Log.setLevel( level );
	return true;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

}; // namespace wosh
